<template>
  <div id="content" class="demo-main" ref="demoMain">
    <canvas id="myCanvas" ref="myCanvas"></canvas>
  </div>
</template>
<script>
import * as THREE from 'three'
import Stats from 'three/examples/jsm/libs/stats.module'

export default {
  data() {
    return {
      renderer: null,
      scene: null,
      camera: null,
      light: null,
      material: null,
      geometry: null,
      mesh: null,
      sphereList: [],
      stats: null,
      animation: null
    }
  },
  mounted(){
    window.addEventListener('resize', this.renderHandle)
    this.renderHandle()
  },
  methods: {
    randomColor(){
      return `rgb(${parseInt(Math.random() * 256)}, ${parseInt(Math.random() * 256)}, ${parseInt(Math.random() * 256)})`
    },
    initStats(id ='content') {
      const stats = new Stats()
      stats.setMode(0)
      stats.domElement.style.position = 'absolute'
      stats.domElement.style.left = 0
      stats.domElement.style.top = 0
      document.getElementById(id).appendChild(stats.domElement)
      return stats
    },
    axesHelper(scene) {
      const axes = new THREE.AxesHelper(10)
      scene.add(axes)
    },
    lightHelper(light, scene) {
      var sphereSize = 1;
      let lightHelper = new THREE.PointLightHelper(light, sphereSize)
      scene.add(lightHelper)
    },
    renderHandle(){
      const  {clientWidth: width, clientHeight: height} = this.$refs.demoMain
      this.renderer = new THREE.WebGLRenderer({
        antialias : true,
        canvas: this.$refs.myCanvas
      })
      this.renderer.setClearColor('#000')
      this.renderer.setSize(width, height)
      this.renderer.shadowMap.enabled = true

      this.scene = new THREE.Scene()

      this.camera = new THREE.PerspectiveCamera(45, width/height, 1, 10000)
      this.camera.position.set(0, 100, 150)
      this.camera.lookAt(this.scene.position)

      // 灯光
      this.light = new THREE.PointLight('#ffffff', 2, 0)
      this.light.position.set(0, 70, 10)
      this.light.castShadow = true
      this.scene.add(this.light)
      
      // 地面
      const PlaneGeometry = new THREE.PlaneGeometry(150, 150)
      const planeMaterial = new THREE.MeshLambertMaterial({
        color: '#ffffff'
      })
      const plane = new THREE.Mesh(PlaneGeometry, planeMaterial)
      plane.rotation.x = -0.5 * Math.PI
      plane.position.set(0, 0, 0)
      plane.receiveShadow = true
      this.scene.add(plane)
      if(this.animation){
        cancelAnimationFrame(this.animation)
      }
      this.stats = this.initStats()
      this.sphereListHandle()
      this.renderScene()
      this.axesHelper(this.scene)
      
      this.lightHelper(this.light, this.scene)
    },
    addSphere() {
      const SphereGeometry = new THREE.SphereGeometry(2, 20, 20)
      const material = new THREE.MeshLambertMaterial({
        color: this.randomColor()
      })
      const sphere = new THREE.Mesh(SphereGeometry, material)
      sphere.position.x = Math.random() * 100 - 50
      sphere.position.y = Math.random() * 100
      // 存储球体的高度
      sphere.number = parseInt(sphere.position.y / 5)
      // 随机球体的高度 最高100 - 50
      sphere.position.z = Math.random() * 100 - 50
      this.scene.add(sphere)
      sphere.castShadow = true
      return sphere
    },
    sphereListHandle(){
      for(let i =0; i<100; i++){
        let sphere = this.addSphere()
        sphere.v = 0;
        sphere.a = -0.01
        sphere.isMoving = true
        this.sphereList.push(sphere)
      }
    },
    renderScene(){
      this.sphereList.forEach(item => {
        this.go(item)
      })
      if(!this.sphereList.some(item => item.isMoving)){
        cancelAnimationFrame(this.animation)
      }
      this.animation = requestAnimationFrame(this.renderScene)
      this.renderer.render(this.scene, this.camera)
      this.stats.update()
    },
    go(item){
      if(item.isMoving) {
        item.position.y += item.v
        item.v += item.a; // 球落体
        // 如果球的高度小于球本身半径，则反弹，高度为原先的0.9倍
        if(item.position.y <= 2){
          item.v = -item.v * 0.9
          item.number = item.number - 1
        }
        if(item.number <=0){
          item.isMoving = false
          item.position.y = 2
        }
      }
    }
  }
}
</script>

<style lang="less">
.demo-main{
  width: 100%;
  height: 100%;
  position: relative;
}
</style>